package cn.legym.garp.gateway.traffic.config;

import cn.legym.garp.gateway.traffic.dynamic.bean.DynamicResourceDefinition;
import com.alibaba.cloud.sentinel.datasource.config.NacosDataSourceProperties;
import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.google.common.collect.Maps;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * create by pipisun on 2021/9/9
 * copyright © 2017-2021 Legym Technology Co.,Ltd. All rights reserve
 * d.
 * file description:
 * <p>
 * 自定义规则加载——nacos数据源
 * <p>
 * 加载并监听
 * <p>
 * spring.cloud.sentinel.dynamic.datasource.nacos.rule -> {@link cn.legym.garp.gateway.traffic.rule.TrafficRule}
 * spring.cloud.sentinel.dynamic.datasource.nacos.resource -> {@link DynamicResourceDefinition}
 * <p>
 * <p>
 * <p>
 * last update by {} on {}
 * update description:
 *
 * @see TrafficConfig.DataSourceType
 */
@Data
@Slf4j
@ConfigurationProperties(prefix = "spring.cloud.sentinel.dynamic.nacos")
public class NacosDataSourceConfig {

    @Autowired
    private ApplicationContext context;

    private Map<TrafficConfig.DataSourceType, NacosDataSourceProperties> datasource = Maps.newHashMap();

    @PostConstruct
    public void init() {
        datasource.forEach((type, prop) -> {
            try {
                ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.MILLISECONDS,
                        new ArrayBlockingQueue<>(1),
                        new NamedThreadFactory("sentinel-dynamic-nacos-ds-listen", true),
                        new ThreadPoolExecutor.DiscardOldestPolicy());
                Converter<String, List<?>> converter = s -> JSON.parseArray(s, type.getDataClazz());

                TrafficDataSourceListener listener = context.getBean(type.listenerClazz());
                Properties properties = new Properties();
                properties.put(PropertyKeyConst.SERVER_ADDR, prop.getServerAddr());
                ConfigService configService = ConfigFactory.createConfigService(properties);
                String values = configService.getConfigAndSignListener(prop.getDataId(), prop.getGroupId(), 10_000, new Listener() {
                    @Override
                    public Executor getExecutor() {
                        return executor;
                    }

                    @Override
                    public void receiveConfigInfo(String configInfo) {
                        listener.updateData(converter.convert(configInfo));
                    }
                });
                listener.updateData(converter.convert(values));
            } catch (Exception e) {
                log.error("", e);
            }
        });
    }
}
